package nz.co.listit.TaxiValet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.location.Address;
import android.location.Geocoder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.preference.PreferenceManager;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ViewFlipper;

public class JobActivity extends ListItResClient implements OnTouchListener {
	public static String PREF_DESTINATION = "destination";
	public static String PREF_PICKUP = "pickup";

	private float _downXValue;
	private ViewFlipper _addressFlipper;
	private String _specialInfo;
	private String _customer;
	private String _number;
	private String _serverErrorMessage;
	private String _pickupAddress;
	private String _destinationAddress;
	private boolean _inProcessNav = false;
	private boolean _useGoogleNavigation;

	private void sendSMS(String phoneNumber, String message) {
		SmsManager sms = SmsManager.getDefault();
		sms.sendTextMessage(phoneNumber, null, message, null, null);
	}

	private Address GetCoord(String address) {
		Geocoder geocoder = new Geocoder(this, Locale.getDefault());
		try {
			List<Address> addresses = geocoder.getFromLocationName(address, 1);

			if (addresses.size() == 1)
				return addresses.get(0);

		} catch (IOException e) {
			// do nothing. Exception means we cannot geocode
		}
		return null;
	}

	private void navigateToAddress(Address address) {
		// launch Google Navigation
		if (address != null) {
			String url;
			if (_useGoogleNavigation) {
				url = "google.navigation:q="
						+ Double.toString(address.getLatitude()) + ","
						+ Double.toString(address.getLongitude());
			} else {
				url = "http://maps.google.com/maps?daddr="
						+ Double.toString(address.getLatitude()) + ","
						+ Double.toString(address.getLongitude());
			}

			Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
			startActivity(intent);
		} else {
			JobActivity.this.runOnUiThread(new Runnable() {

				public void run() {
					AlertDialog.Builder builder = new AlertDialog.Builder(
							JobActivity.this);

					builder.setMessage("Unable to navigate to address.")

							.setCancelable(false)

							.setPositiveButton("OK",
									new DialogInterface.OnClickListener() {
										public void onClick(
												DialogInterface dialog, int d) {
											dialog.cancel();
										}

									});
					AlertDialog alert = builder.create();
					alert.show();
				}

			});
		}
	}

	private void onRefreshClick() {
		_progDlg = ProgressDialog.show(this, "",
				"Retrieving job from the server.  Please wait...", true);

		// now login to List-It server
		Thread thread = new Thread(JobActivity.this);
		thread.start();
	}

	private void onSMSClick() {
		// must be a message from the server
		final Dialog dialog = new Dialog(JobActivity.this);
		dialog.setContentView(R.layout.smsmessage);
		dialog.setTitle(String.format("Send message to: %s (%s)", _customer,
				_number));

		// get the taxi's unique identifier
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(this);
		
		final String taxiIdentifier = sp.getString("taxi_identifier", "");

		dialog.setCancelable(true);
		
		Button btnConfirm = (Button) dialog.findViewById(R.id.btnSmsConfirmJob);
		btnConfirm.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				JobActivity.this.sendSMS(_number, String.format("Job confirmation. Pickup at: \n%s.  \n%s",
						_pickupAddress, taxiIdentifier));
				dialog.cancel();
			}
		});
		
		Button btnArrival = (Button) dialog.findViewById(R.id.btnSmsArrival);
		btnArrival.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				JobActivity.this.sendSMS(_number, String.format("Your taxi has arrived!. %s", taxiIdentifier));
				dialog.cancel();
			}
		});

		dialog.show();
	}

	private void onTrashJob() {
		_progDlg = ProgressDialog.show(this, "",
				"Deleting job.  Please wait...", true);

		new Thread(new Runnable() {
			public void run() {
				ListItServerClient ltClient = new ListItServerClient();

				List<NameValuePair> qparams = new ArrayList<NameValuePair>();

				try {
					// add device ID
					qparams.add(new BasicNameValuePair("deviceID",
							JobActivity.this.getDeviceID()));
					// call web service
					JSONObject result = ltClient.queryListItService(
							"TerminateJob", qparams);

					Message msg = new Message();
					msg.what = result.getInt(KEY_SERVER_RET_CODE);
					msg.obj = result;
					handler.sendMessage(msg);

				} catch (JSONException e) {
					Log.e(TAG, String.format(FMT_ERROR, "onTrashJob",
							KEY_SERVER_RET_CODE));
				}
			}
		}).start();
	}

	private void onPassOnJobClick() {
		_progDlg = ProgressDialog.show(this, "",
				"Releasing job.  Please wait...", true);

		new Thread(new Runnable() {
			public void run() {
				ListItServerClient ltClient = new ListItServerClient();

				List<NameValuePair> qparams = new ArrayList<NameValuePair>();

				try {
					// add device ID
					qparams.add(new BasicNameValuePair("deviceID",
							JobActivity.this.getDeviceID()));
					// call web service
					JSONObject result = ltClient.queryListItService(
							"WithdrawJob", qparams);

					Message msg = new Message();
					msg.what = result.getInt(KEY_SERVER_RET_CODE);
					msg.obj = result;
					handler.sendMessage(msg);

				} catch (JSONException e) {
					Log.e(TAG, String.format(FMT_ERROR, "onPassOnJobClick",
							KEY_SERVER_RET_CODE));
				}
			}
		}).start();
	}

	private void onCompleteJobClick() {
		_progDlg = ProgressDialog.show(this, "",
				"Completing job.  Please wait...", true);

		new Thread(new Runnable() {
			public void run() {
				ListItServerClient ltClient = new ListItServerClient();

				List<NameValuePair> qparams = new ArrayList<NameValuePair>();

				try {
					// add device ID
					qparams.add(new BasicNameValuePair("deviceID",
							JobActivity.this.getDeviceID()));
					// call web service
					JSONObject result = ltClient.queryListItService(
							"CompleteJob", qparams);

					Message msg = new Message();
					msg.what = result.getInt(KEY_SERVER_RET_CODE);
					msg.obj = result;
					handler.sendMessage(msg);

				} catch (JSONException e) {
					Log.e(TAG, String.format(FMT_ERROR, "onTrashJob",
							KEY_SERVER_RET_CODE));
				}
			}
		}).start();
	}

	@Override
	protected void onOKResult(JSONObject json) {
		if (JobActivity.this._progDlg != null)
			JobActivity.this._progDlg.dismiss();

		try {
			EditText editText;

			/*
			 * -----------------------*\ DO PICKUP * \* ----------------------
			 */
			editText = (EditText) this.findViewById(R.id.etAddressPickup);
			_pickupAddress = json.getString(KEY_SERVER_PICKUP);
			editText.setText(_pickupAddress);
			editText.setOnTouchListener(JobActivity.this);

			// hide or show the special info indicator
			ImageView info = (ImageView) this.findViewById(R.id.ivInfo);
			_specialInfo = json.getString(KEY_SERVER_SPECIAL_INSTRUCTION);

			if (_specialInfo.length() != 0)
				info.setVisibility(View.VISIBLE);
			else
				info.setVisibility(View.INVISIBLE);

			_number = json.getString(KEY_SERVER_MOBILE_NUMBER);

			_customer = json.getString(KEY_SERVER_CUSTOMER);

			/*
			 * ----------------------- DO DESTINATION ----------------------
			 */
			editText = (EditText) this.findViewById(R.id.etAddressDestination);
			_destinationAddress = json.getString(KEY_SERVER_DESTINATION);
			editText.setText(_destinationAddress);
			editText.setOnTouchListener(JobActivity.this);

			// remove the status bar notification
			NotificationManager notificationMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
			notificationMgr.cancelAll();

		} catch (JSONException e) {
			Log.e(TAG, String.format(FMT_ERROR, "onOKResult",
					KEY_SERVER_C2DM_EMAIL));
		}
	}

	// called on JOB_TERMINATE
	@Override
	protected void onJobTerminate(JSONObject json) {
		if (_progDlg != null)
			_progDlg.dismiss();

		this.finish();
	}

	// called on JOB_WITHDRAW
	@Override
	protected void onJobWithdraw(JSONObject json) {
		if (_progDlg != null)
			_progDlg.dismiss();

		this.finish();
	}

	// called on JOB_COMPLETE
	@Override
	protected void onJobComplete(JSONObject json) {
		if (_progDlg != null)
			_progDlg.dismiss();
		this.finish();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.job_menu, menu);
		return true;
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.job);
		_addressFlipper = (ViewFlipper) findViewById(R.id.vpAddress);

		// set debug flag
		Bundle bundle = this.getIntent().getExtras();
		_debug = bundle.getBoolean(KEY_SERVER_DEBUG_TAXI);

		// show debug indicator
		TextView tvDemo1 = (TextView) findViewById(R.id.tvDemo1);
		TextView tvDemo2 = (TextView) findViewById(R.id.tvDemo2);

		if (_debug) {
			tvDemo1.setVisibility(View.VISIBLE);
			tvDemo2.setVisibility(View.VISIBLE);
		} else {
			tvDemo1.setVisibility(View.INVISIBLE);
			tvDemo2.setVisibility(View.INVISIBLE);
		}

		// check if use wants to use the Google Map Navigation
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(this);
		_useGoogleNavigation = sp.getBoolean("google_navigation", false);

		_progDlg = ProgressDialog.show(JobActivity.this, "",
				"Obtaining customer details from server. Please wait...", true);

		// now login to List-It server
		Thread thread = new Thread(this);
		thread.start();
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		/*
		 * IMPORTANT!!! You need this code here because this stops the onCreate
		 * to get called when the phone goes into sleep mode. When the onCreate
		 * is called while the phone is going to sleep, the activity will crash!
		 */
		super.onConfigurationChanged(newConfig);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle item selection
		switch (item.getItemId()) {
		case R.id.jobRefresh:
			onRefreshClick();
			return true;

		case R.id.jobSMS:
			onSMSClick();
			return true;

		case R.id.jobTerminate:
			onTrashJob();
			return true;

		case R.id.jobWithdraw:
			onPassOnJobClick();
			return true;

		case R.id.jobComplete:
			onCompleteJobClick();
			return true;

		default:
			return super.onOptionsItemSelected(item);
		}
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {

		// we want to inform the user before we terminate the application
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			// disable back button
			return true;
		} else {
			return super.onKeyDown(keyCode, event);
		}
	}

	public void onInfoClick(View v) {
		AlertDialog.Builder builder = new AlertDialog.Builder(JobActivity.this);
		builder.setMessage(_specialInfo).setTitle("Special Instruction")

		.setCancelable(false)

		.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int d) {
				// now login to List-It server
				Thread thread = new Thread(JobActivity.this);
				thread.start();
			}

		});

		AlertDialog alert = builder.create();
		alert.show();
	}

	public void onPickupMapClick(View v) {
		if (_inProcessNav)
			return;

		JobActivity.this._progDlg = ProgressDialog.show(this, "",
				"Processing.  Please wait...", true);

		_inProcessNav = true;
		try {
			new Thread(new Runnable() {
				public void run() {
					Address address = null;
					address = GetCoord(_pickupAddress);

					if (JobActivity.this._progDlg != null)
						JobActivity.this._progDlg.dismiss();

					navigateToAddress(address);
				}
			}).start();
		} finally {
			_inProcessNav = false;
		}
	}

	public void onDestinationMapClick(View v) {
		if (_inProcessNav)
			return;
		JobActivity.this._progDlg = ProgressDialog.show(this, "",
				"Processing.  Please wait...", true);

		_inProcessNav = true;
		try {
			new Thread(new Runnable() {
				public void run() {
					Address address = null;
					address = GetCoord(_destinationAddress);

					if (JobActivity.this._progDlg != null)
						JobActivity.this._progDlg.dismiss();

					navigateToAddress(address);
				}
			}).start();
		} finally {
			_inProcessNav = false;
		}
	}

	public boolean onTouch(View v, MotionEvent event) {
		// Toast.makeText(JobActivity.this, "Left Swipe",
		// Toast.LENGTH_SHORT).show();

		// Get the action that was done on this touch event
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN: {
			// store the X value when the user's finger was pressed down
			_downXValue = event.getX();
			break;
		}

		case MotionEvent.ACTION_UP: {
			// Get the X value when the user released his/her finger
			float currentXValue = event.getX();

			// going backwards: pushing stuff to the right
			if (_downXValue < currentXValue) {
				_addressFlipper.setInAnimation(AnimationHelper
						.inFromLeftAnimation());
				_addressFlipper.setOutAnimation(AnimationHelper
						.outToRightAnimation());
				_addressFlipper.showNext();
			}

			// going forwards: pushing stuff to the left
			if (_downXValue > currentXValue) {
				_addressFlipper.setInAnimation(AnimationHelper
						.inFromRightAnimation());
				_addressFlipper.setOutAnimation(AnimationHelper
						.outToLeftAnimation());
				_addressFlipper.showPrevious();
			}
			break;
		}
		}

		return false;
	}

	@Override
	public void run() {
		if (_pickupAddress != null) // if we've already got the job then exit
			return;

		ListItServerClient ltClient = new ListItServerClient();

		List<NameValuePair> qparams = new ArrayList<NameValuePair>();

		try {
			// add device ID
			qparams.add(new BasicNameValuePair("deviceID", this.getDeviceID()));
			// call web service
			JSONObject result = ltClient.queryListItService("GetJob", qparams);

			int retCode = result.getInt(KEY_SERVER_RET_CODE);

			if (!result.isNull(KEY_SERVER_MESSAGE))
				_serverErrorMessage = result.getString(KEY_SERVER_MESSAGE);

			// if the return code is not OK, it means we have comms
			// error so ask the user if they want to try again
			if (retCode == WEBSERVER_MESSAGES.JOB_EXPIRED.ordinal()) {
				JobActivity.this.runOnUiThread(new Runnable() {

					public void run() {
						AlertDialog.Builder builder = new AlertDialog.Builder(
								JobActivity.this);
						builder.setMessage(
								"The job you are requesting for has expired.")
								.setTitle("Job Expired")

								.setCancelable(false)

								.setPositiveButton("OK",
										new DialogInterface.OnClickListener() {
											public void onClick(
													DialogInterface dialog,
													int d) {
												dialog.cancel();
												JobActivity.this.finish();
											}

										});
						AlertDialog alert = builder.create();
						alert.show();
					}
				});
			} else if (retCode != WEBSERVER_MESSAGES.OK.ordinal()) {

				JobActivity.this.runOnUiThread(new Runnable() {

					public void run() {
						AlertDialog.Builder builder = new AlertDialog.Builder(
								JobActivity.this);

						String errorMsg = "Unable to retrieve job from the server. Do you want to try again?";

						if (JobActivity.this._debug) {
							errorMsg = JobActivity.this._serverErrorMessage;
						}

						builder.setMessage(errorMsg)
								.setTitle("Cannot obtain Job")

								.setCancelable(false)

								.setPositiveButton("Yes",
										new DialogInterface.OnClickListener() {
											public void onClick(
													DialogInterface dialog,
													int d) {
												// now login to List-It server
												Thread thread = new Thread(
														JobActivity.this);
												thread.start();
											}

										})
								.setNegativeButton("No",
										new DialogInterface.OnClickListener() {
											public void onClick(
													DialogInterface dialog,
													int whichButton) {
												// cannot continue at this
												// point. Let's close the
												// application
												dialog.cancel();
												JobActivity.this.finish();
											}
										});

						AlertDialog alert = builder.create();
						alert.show();
					}
				});
			} else {
				Message msg = new Message();
				msg.what = result.getInt(KEY_SERVER_RET_CODE);
				msg.obj = result;
				handler.sendMessage(msg);
			}

		} catch (JSONException e) {
			Log.e(TAG, String.format(FMT_ERROR, "LoginActivity.run",
					KEY_SERVER_RET_CODE));
		}
	}
}
